home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / news / readers / nn / nn6.4.patch13 < prev    next >
Encoding:
Text File  |  1991-02-07  |  59.8 KB  |  2,366 lines

  1.          This is an official patch to nn release 6.4
  2.          -------------------------------------------
  3.  
  4.                    PATCH #13
  5.  
  6.                 Priority: MEDIUM
  7.  
  8.  
  9. This patch contains mainly minor bugs fixes and some new features.
  10. Specifically, when new groups are created, the GROUPS file is now
  11. rewritten rather than just appended to; this is done to minimize the
  12. risk that the MASTER and GROUPS files lose their 1:1 relationship.
  13.  
  14. The handling of the GATE file used to communicate between nnadmin and
  15. nnmaster has been improved significantly to detect and possily fix
  16. problems where permissions would prevent successful communication
  17. (typically preventing expire on the database).
  18.  
  19. The decoding of Date: headers has been reworked to parse more time
  20. zones (and do it correctly), to make it easier to add new time zones,
  21. and to make it handle 4 digit years.
  22.  
  23. The keyboard input handling is also completely reworked to support
  24. sys5 network environments where the VMIN/VTIME mechanism is often
  25. unreliable, and consequently multi-keys are not recognized properly.
  26.  
  27. The "enter last read group" feature introduced in patch 12 where nn
  28. will now automatically wrap around the presentation sequence to allow
  29. you to read groups before the remembered group.
  30.  
  31. This patch includes some support for Apollo's Domain/OS and a new
  32. s-apollo.h file.  The patch 2.0 program should be able to create this
  33. file - if it can't, get a newer version of patch.  However, you can
  34. ignore any complains from patch about not being able to create the
  35. conf directory (it already exists).
  36.  
  37. As usual, all changes are described in the updated RELEASE_NOTES file
  38. (read that for more details about this patch).  Thanks to all who
  39. reported bugs and provided fixes.
  40.  
  41. To apply this patch, use nn's :patch command, or run this command from
  42. the shell in the root of the nn source tree:
  43.     patch -p0 < this-article
  44.  
  45. Then run "make all" and "./inst u".
  46.  
  47. ++Kim Storm
  48.  
  49. ===================================================================
  50.  
  51. *** ./LAST/MANIFEST    Sun May  6 18:19:12 1990
  52. --- MANIFEST    Wed Jan 30 18:23:07 1991
  53. ***************
  54. *** 36,41 ****
  55. --- 36,42 ----
  56.   conf/m-vax.h              22    For VAX family
  57.   conf/s-3b1g.h             22    For 3b1 (unix-pc) with GCC.
  58.   conf/s-aix221.h           14    For AIX 2.2.1
  59. + conf/s-apollo.h        6.4.13    For Apollo Domain/OS
  60.   conf/s-aux1-1.h           22    For A/UX 1.1
  61.   conf/s-bsd4-2.h           20    For 4.2 BSD and Ultrix systems
  62.   conf/s-bsd4-3.h           22    For 4.3 BSD systems
  63. *** ./LAST/answer.c    Wed Nov  7 15:54:22 1990
  64. --- answer.c    Wed Nov 28 21:06:58 1990
  65. ***************
  66. *** 77,83 ****
  67. --- 77,87 ----
  68.       now = cur_time();
  69.       date = asctime(gmtime(&now));
  70.       date[3] = date[7] = date[10] = date[19] = date[24] = NUL;
  71. + #ifdef NNTP_PATH_HOSTNAME
  72. +     strncpy(host, NNTP_PATH_HOSTNAME, 64);
  73. + #else
  74.       gethostname(host, 64);
  75. + #endif
  76.   
  77.       fprintf(t, "Path: %s!%s\n", host, user_name());
  78.       fprintf(t, "Date: %s %s %s %s GMT\n", date+8, date+4, date+22, date+11);
  79. ***************
  80. *** 319,324 ****
  81. --- 323,330 ----
  82.       extern char *nntp_get_filename();
  83.   #endif
  84.   
  85. +     if (strcmp(prog, "COMPLETE") == 0) goto no_params;
  86.       param = open_file(relative(nn_directory, ".param"), OPEN_CREATE);
  87.       if (param == NULL) {
  88.       strcpy(delayed_msg, "cannot create .param file for aux script");
  89. ***************
  90. *** 381,386 ****
  91. --- 387,393 ----
  92.   
  93.       fclose(param);
  94.   
  95. +  no_params:
  96.       stop_usage();
  97.   
  98.       /* OBS: relative() returns ptr to static data below */
  99. ***************
  100. *** 387,392 ****
  101. --- 394,400 ----
  102.       *ap++ = "nnaux";
  103.       *ap++ = script != NULL ? script : relative(lib_directory, "aux");
  104.       *ap++ = prog;
  105. +     *ap++ = temp_file;
  106.       *ap++ = NULL;
  107.   
  108.       if (execute(SHELL, args, 1)) {
  109. ***************
  110. *** 455,460 ****
  111. --- 463,488 ----
  112.       news_header_buffer nhbuf, dhbuf;
  113.       flag_type st_flag = 0;
  114.   
  115. +     if (file_exist(relative(nn_directory, "hold.work"), (char *)NULL)) {
  116. +     int ans;
  117. +     prompt("\1An uncompleted reponse exists\1 - complete now? ");
  118. +     if ((ans = yes(1)) < 0) return 0;
  119. +     if (ans) {
  120. +         if (ah && ah->a_group) init_group(ah->a_group);
  121. +         new_temp_file();
  122. +         aux_sh(ah, (char *)NULL, "COMPLETE", (char *)NULL, (char *)NULL,
  123. +            "Response%s posted", 0);
  124. +         return 1;
  125. +     }
  126. +     prompt("Remove uncompleted reponse? ");
  127. +     if ((ans = yes(1)) < 0) return 0;
  128. +     if (ans) {
  129. +         unlink(relative(nn_directory, "hold.work"));
  130. +         unlink(relative(nn_directory, "hold.param"));
  131. +     }
  132. +     }
  133.       first_action = "edit";
  134.       edit_message = 1;
  135.       append_sig = 0;
  136. ***************
  137. *** 788,793 ****
  138. --- 816,822 ----
  139.   
  140.       ed_line = -1;
  141.   
  142. +     new_temp_file();
  143.       if (aux_sh(ah, (char *)NULL, "cancel", news.ng_ident, current_group->group_name,
  144.              "Article%s cancelled", 0))
  145.       return -1;
  146. *** ./LAST/aux.sh    Wed Nov  7 15:54:23 1990
  147. --- aux.sh    Mon Dec 10 14:33:03 1990
  148. ***************
  149. *** 4,10 ****
  150.   trap : 2 3
  151.   
  152.   PATH=/bin:$PATH
  153. - export PATH
  154.   
  155.   # Paramaters transferred from nn via .param file:
  156.   #    ART_ID        Article id to cancel
  157. --- 4,9 ----
  158. ***************
  159. *** 31,47 ****
  160.   
  161.   CC=""
  162.   
  163. ! . ${HOME}/.nn/.param
  164. ! # first argument is operation to be performed:
  165. ! OPERATION=$1
  166.   
  167.   # first we handle 'cancel'
  168.   
  169.   case "$OPERATION" in
  170.   cancel)
  171. !   $INEWS -h  << EOF > /tmp/nn$$c 2>&1
  172.   Newsgroups: $GROUP
  173.   Subject: cancel $ART_ID
  174.   Control: cancel $ART_ID
  175. --- 30,52 ----
  176.   
  177.   CC=""
  178.   
  179. ! if [ "$1" = "COMPLETE" ] ; then
  180. !   . ${HOME}/.nn/hold.param
  181. !   WORK="$2"
  182. !   EMPTY_CHECK=false
  183. !   cp ${HOME}/.nn/hold.work $WORK
  184. !   rm -f ${HOME}/.nn/hold.*
  185. ! else
  186. !  . ${HOME}/.nn/.param
  187. !  OPERATION=$1
  188. ! fi
  189.   
  190.   # first we handle 'cancel'
  191.   
  192.   case "$OPERATION" in
  193.   cancel)
  194. !   TRACE="$2"
  195. !   $INEWS -h  << EOF > $TRACE 2>&1
  196.   Newsgroups: $GROUP
  197.   Subject: cancel $ART_ID
  198.   Control: cancel $ART_ID
  199. ***************
  200. *** 52,60 ****
  201.     x=$?
  202.     case $x in
  203.       0) ;;
  204. !     *) echo '' ; cat /tmp/nn$$c ; sleep 2 ;;
  205.     esac
  206. !   rm -f /tmp/nn$$c
  207.     exit $x
  208.     ;;
  209.   post|follow)
  210. --- 57,65 ----
  211.     x=$?
  212.     case $x in
  213.       0) ;;
  214. !     *) echo '' ; cat $TRACE ; sleep 2 ;;
  215.     esac
  216. !   rm -f $TRACE
  217.     exit $x
  218.     ;;
  219.   post|follow)
  220. ***************
  221. *** 85,90 ****
  222. --- 90,96 ----
  223.     pr="$pr c)c"
  224.   fi
  225.   pr="$pr e)dit"
  226. + pr="$pr h)old"
  227.   if [ -n "${SPELL_CHECKER}" ] ; then
  228.     pr="$pr i)spell"
  229.   fi
  230. ***************
  231. *** 180,185 ****
  232. --- 186,206 ----
  233.       echo "Warning: no $LOOKFOR line in article"
  234.         fi
  235.       fi
  236. +     ;;
  237. +   h*)
  238. +     ${AWK} 'END{printf "Complete response later: (y) "}' < /dev/null
  239. +     read act
  240. +     case "$act" in
  241. +     ""|y*)
  242. +     cp $WORK ${HOME}/.nn/hold.work
  243. +     cp ${HOME}/.nn/.param ${HOME}/.nn/hold.param
  244. +     echo "OPERATION=$OPERATION" >> ${HOME}/.nn/hold.param
  245. +     if [ -n "$COPY" ] ; then
  246. +       rm -f $COPY
  247. +     fi
  248. +     exit 22 ;;
  249. +     esac
  250.       ;;
  251.   
  252.     i*)
  253. *** /dev/null    Wed Feb  6 15:10:01 1991
  254. --- conf/s-apollo.h    Wed Jan 30 19:45:56 1991
  255. ***************
  256. *** 0 ****
  257. --- 1,38 ----
  258. + /*
  259. +  *    This version is for Apollo Domain/OS systems running BSD 4.3.
  260. +  *    From: mmitchel@digi.lonestar.org (Mitch Mitchell)
  261. +  */
  262. + #include "s-bsd4-3.h"
  263. + /*
  264. +  *    special sleep function that terminates following
  265. +  *      the receipt of a signal  (needed for BSD Unix).
  266. +  */
  267. + #define HAVE_HARD_SLEEP
  268. + /*
  269. +  *    Specify where the Korne Shell is. (instead of Borne Shell)
  270. +  *    The Bourne Shell is somewhat unreliable (at SR10.2).
  271. +  */
  272. + #ifdef  SHELL
  273. + #undef  SHELL
  274. + #endif
  275. + #define SHELL        "/bin/ksh"
  276. + /*
  277. +  *    Allow specification of file names to begin with a double
  278. +  *      slash "//" so that Apollo node names of form "//node" can
  279. +  *      occur in folder and file specifications.
  280. +  */
  281. + #define ALLOW_LEADING_DOUBLE_SLASH
  282. + /*
  283. +  *    Cause nnmaster to keep a CLIENT copy of the MASTER file to overcome
  284. +  *    problems with network write access.
  285. +  */
  286. + #define APOLLO_DOMAIN_OS
  287. *** ./LAST/conf/s-bsd4-2.h    Mon Apr 23 18:32:50 1990
  288. --- conf/s-bsd4-2.h    Wed Nov 28 13:36:54 1990
  289. ***************
  290. *** 56,67 ****
  291.   #undef    SIGNAL_HANDLERS_ARE_VOID    /* */
  292.   
  293.   /*
  294. -  *    Define MICRO_ALARM to timeout in 0.1 seconds if possible
  295. -  */
  296. - #define MICRO_ALARM()    alarm(1)    /* could use setitimer ... */
  297. - /*
  298.    *    Define if your system has BSD like job control (SIGTSTP works)
  299.    */
  300.   
  301. --- 56,61 ----
  302. *** ./LAST/conf/s-bsd4-3.h    Sat Mar 31 23:13:01 1990
  303. --- conf/s-bsd4-3.h    Wed Nov 28 15:03:12 1990
  304. ***************
  305. *** 5,15 ****
  306.   #include "s-bsd4-2.h"
  307.   
  308.   /*
  309. !  *    Define MICRO_ALARM to timeout in 0.1 seconds if possible
  310.    */
  311.   
  312. ! #undef    MICRO_ALARM
  313. ! #define MICRO_ALARM()    ualarm(100000,0)    /* BSD 4.3 */
  314.   
  315.   /*
  316.    *    Define if your system has a 4.3BSD like syslog library.
  317. --- 5,14 ----
  318.   #include "s-bsd4-2.h"
  319.   
  320.   /*
  321. !  *    Define if your system has a 4.3BSD like ualarm call.
  322.    */
  323.   
  324. ! #define HAVE_UALARM
  325.   
  326.   /*
  327.    *    Define if your system has a 4.3BSD like syslog library.
  328. *** ./LAST/conf/s-fortune.h    Tue Sep 18 12:44:51 1990
  329. --- conf/s-fortune.h    Wed Nov 28 13:36:53 1990
  330. ***************
  331. *** 60,72 ****
  332.   #define    RESET_SIGNAL_WHEN_CAUGHT    /* */
  333.   
  334.   /*
  335. -  *    Define MICRO_ALARM to timeout in 0.1 seconds if possible
  336. -  */
  337. - #define MICRO_ALARM()    alarm(1)    /* System V */
  338. - /*#define MICRO_ALARM()    ualarm(100000,0)    /* BSD 4.3 */
  339. - /*
  340.    *    Define if your system has BSD like job control (SIGTSTP works)
  341.    */
  342.   
  343. --- 60,65 ----
  344. *** ./LAST/conf/s-sunos3.h    Sat Mar 31 23:13:02 1990
  345. --- conf/s-sunos3.h    Wed Nov 28 15:03:12 1990
  346. ***************
  347. *** 9,16 ****
  348.   #define    HAVE_STRCHR
  349.   
  350.   /*
  351. !  *    Define MICRO_ALARM to timeout after 0.1 seconds if possible
  352.    */
  353.   
  354. ! #undef    MICRO_ALARM
  355. ! #define MICRO_ALARM()    ualarm(100000,0)    /* BSD 4.3 */
  356. --- 9,15 ----
  357.   #define    HAVE_STRCHR
  358.   
  359.   /*
  360. !  *    Define if your system has a 4.3BSD like ualarm call.
  361.    */
  362.   
  363. ! #define HAVE_UALARM
  364. *** ./LAST/conf/s-sunos4-0.h    Mon Apr 23 18:32:47 1990
  365. --- conf/s-sunos4-0.h    Mon Nov 19 14:11:06 1990
  366. ***************
  367. *** 8,13 ****
  368. --- 8,17 ----
  369.   
  370.   #define HAVE_STRCHR            /* */
  371.   
  372. + #ifdef sun4
  373. + #define COMPILER_FLAGS -misalign
  374. + #endif
  375.   /*
  376.    *    Define if a signal handler has type void (see signal.h)
  377.    */
  378. *** ./LAST/conf/s-template.h    Tue Jun 12 11:46:27 1990
  379. --- conf/s-template.h    Wed Jan 30 20:05:27 1991
  380. ***************
  381. *** 82,92 ****
  382.   /* #define FAKE_INTERRUPT    /* */
  383.   
  384.   /*
  385. !  *    Define MICRO_ALARM to timeout in 0.1 seconds if possible
  386. !  *    It is not used on systems with the TERMIO interface (sys V).
  387.    */
  388.   
  389. ! /*#define MICRO_ALARM()    ualarm(100000,0)    /* BSD 4.3 */
  390.   
  391.   /*
  392.    *    Define if your system has BSD like job control (SIGTSTP works)
  393. --- 82,102 ----
  394.   /* #define FAKE_INTERRUPT    /* */
  395.   
  396.   /*
  397. !  *    Define HAVE_HARD_SLEEP if sending a SIGALRM isn't enough to
  398. !  *    interrupt a sleep() call - typical symptom is that nnadmin W
  399. !  *    doesn't wakeup the nnmaster.
  400.    */
  401.   
  402. ! /* #define HAVE_HARD_SLEEP        /* BSD ? */
  403. ! /*
  404. !  *    Define HAVE_UALARM if your system has a 4.3 BSD like ualarm() call.
  405. !  *    Else define MICRO_ALARM(n) to timeout in n/10 seconds if possible.
  406. !  *    Don't define either if system only has the standard alarm() call.
  407. !  */
  408. ! /* #define HAVE_UALARM            /* BSD 4.3 */
  409. ! /* #define MICRO_ALARM(n)    xxxx(n)    /* */
  410.   
  411.   /*
  412.    *    Define if your system has BSD like job control (SIGTSTP works)
  413. *** ./LAST/conf/s-umipsb.h    Wed May  2 09:38:44 1990
  414. --- conf/s-umipsb.h    Wed Nov 28 15:03:12 1990
  415. ***************
  416. *** 57,67 ****
  417.   #undef    RESET_SIGNAL_WHEN_CAUGHT    /* */
  418.   
  419.   /*
  420. !  *    Define MICRO_ALARM to timeout in 0.1 seconds if possible
  421.    */
  422.   
  423. ! /*#define MICRO_ALARM()    alarm(1)    /* System V */
  424. ! #define MICRO_ALARM()    ualarm(100000,0)    /* BSD 4.3 */
  425.   
  426.   /*
  427.    *    Define if your system has BSD like job control (SIGTSTP works)
  428. --- 57,66 ----
  429.   #undef    RESET_SIGNAL_WHEN_CAUGHT    /* */
  430.   
  431.   /*
  432. !  *    Define if your system has a 4.3BSD like ualarm call.
  433.    */
  434.   
  435. ! #define HAVE_UALARM
  436.   
  437.   /*
  438.    *    Define if your system has BSD like job control (SIGTSTP works)
  439. *** ./LAST/config.h-dist    Tue May 29 18:36:22 1990
  440. --- config.h-dist    Wed Nov 28 21:06:58 1990
  441. ***************
  442. *** 86,91 ****
  443. --- 86,99 ----
  444.   
  445.   #define NNTP_MINI_INEWS_HEADER    /* uses "broken" mini-inews */
  446.   
  447. + /*
  448. +  *    Define NNTP_PATH_HOSTNAME to force a specific hostname into the
  449. +  *    Path: header generated when NNTP_MINI_INEWS_HEADER is defined.
  450. +  *    This is useful for multi-machine sites with one mail/news gateway.
  451. +  */
  452. + /* #define NNTP_PATH_HOSTNAME    "puthostnamehere"    /* */
  453.   
  454.   /***************** OPERATING SYSTEM DEPENDENT DEFINITIONS *******************
  455.    *
  456. *** ./LAST/db.c    Wed Nov  7 15:54:25 1990
  457. --- db.c    Wed Feb  6 14:57:00 1991
  458. ***************
  459. *** 140,145 ****
  460. --- 140,147 ----
  461.   
  462.       if (group_file != NULL && (mode & OPEN_CREATE)) {
  463.       fprintf(group_file, 
  464. + "#\n#\tNEVER MODIFY THIS FILE WHILE nnmaster IS RUNNING\n");
  465. +     fprintf(group_file, 
  466.   "#\n#\tRUN 'nnmaster -G' AFTER MODIFYING THIS FILE\n");
  467.       fprintf(group_file, 
  468.   "#\n#\tDO NOT REMOVE OR REORDER ANY LINES IN THIS FILE\n#\n");
  469. ***************
  470. *** 160,170 ****
  471.   register group_header *gh;
  472.   {
  473.       char flags[16], *fp;
  474. -     int was_open = (group_file != NULL);
  475. -     if (!was_open) open_groups(OPEN_UPDATE|MUST_EXIST);
  476.   
  477. -     fseek(group_file, (off_t)0, 2);
  478.       if (gh->group_name[0] == NUL) {
  479.       fputc('@', group_file);
  480.       goto out;
  481. --- 162,168 ----
  482. ***************
  483. *** 197,205 ****
  484.   
  485.    out:
  486.       fputc(NL, group_file);
  487. !     fflush(group_file);
  488.   
  489. !     if (!was_open) close_groups();
  490.   }
  491.   
  492.   static char *mk_archive_file(gh, cp, logerr)
  493. --- 195,223 ----
  494.   
  495.    out:
  496.       fputc(NL, group_file);
  497. ! }
  498. ! db_rewrite_groups(save_groups, group_list)
  499. ! int save_groups;
  500. ! group_header *group_list;
  501. ! {
  502. !     register group_header *gh;
  503.   
  504. !     if (save_groups)
  505. !     if (save_old_file(relative(db_directory, "GROUPS"), "~") < 0)
  506. !         sys_error("Cannot rename GROUPS file");
  507. !     
  508. !     open_groups(OPEN_CREATE|MUST_EXIST);
  509. !     if (group_list != NULL) {
  510. !     for (gh = group_list->next_group; gh != NULL; gh = gh->next_group)
  511. !         db_append_group(gh);
  512. !     } else {
  513. !     Loop_Groups_Header(gh) {
  514. !         db_append_group(gh);
  515. !     }
  516. !     }
  517. !     close_groups();
  518.   }
  519.   
  520.   static char *mk_archive_file(gh, cp, logerr)
  521. ***************
  522. *** 253,258 ****
  523. --- 271,278 ----
  524.   
  525.       if (trust_master) {
  526.       cp = name + gh->group_name_length;
  527. +     if (*cp == NUL || !isspace(*cp))
  528. +         sys_error("MASTER/GROUPS conflict: %d/%s", gh->group_num, line);
  529.       } else {
  530.       /* parse GROUPS line */
  531.   
  532. ***************
  533. *** 379,384 ****
  534. --- 399,416 ----
  535.   static FILE *master_file = NULL;
  536.   static int db_sequential = 0;
  537.   
  538. + #ifdef APOLLO_DOMAIN_OS
  539. + static make_master_copy()
  540. + {
  541. +     char client_path[FILENAME];
  542. +     int n;
  543. +     
  544. +     strcpy(client_path,relative(db_directory, "CLIENT"));
  545. +     if ((n = copy_file(relative(db_directory, "MASTER"), client_path, 0)) < 0)
  546. +     log_entry('R', "Copy of MASTER to CLIENT failed (err=%d)", n);
  547. + }
  548. + #endif
  549.   open_master(mode)
  550.   int mode;
  551.   {
  552. ***************
  553. *** 387,392 ****
  554. --- 419,429 ----
  555.   
  556.       close_master();
  557.   
  558. + #ifdef APOLLO_DOMAIN_OS
  559. +     if (who_am_i != I_AM_MASTER && who_am_i != I_AM_ADMIN)
  560. +     master_file = open_file(relative(db_directory, "CLIENT"), mode|MUST_EXIST);
  561. +     else
  562. + #endif
  563.       master_file = open_file(relative(db_directory, "MASTER"), mode|MUST_EXIST);
  564.   
  565.       db_sequential = 0;
  566. ***************
  567. *** 745,750 ****
  568. --- 782,790 ----
  569.   #endif
  570.   
  571.       fflush(master_file);
  572. + #ifdef APOLLO_DOMAIN_OS
  573. +     if (who_am_i == I_AM_MASTER) make_master_copy();
  574. + #endif
  575.       return;
  576.   
  577.    err:
  578. ***************
  579. *** 825,830 ****
  580. --- 865,873 ----
  581.       goto err;
  582.   #endif
  583.       fflush(master_file);
  584. + #ifdef APOLLO_DOMAIN_OS
  585. +     if (who_am_i == I_AM_MASTER) make_master_copy();
  586. + #endif
  587.       return;
  588.   
  589.    err:
  590. *** ./LAST/doc/RELEASE_NOTES    Wed Nov  7 15:54:27 1990
  591. --- doc/RELEASE_NOTES    Tue Feb  5 16:48:32 1991
  592. ***************
  593. *** 1325,1331 ****
  594. --- 1325,1445 ----
  595.   From:    itkin@guinan.transact.com (Steven List)
  596.   Fixed:    Patch #12 [answer.c]
  597.   
  598. + Prog:    nnmaster
  599. + Title:    Index file was not closed if index was not found (file too short)
  600. + From:    KFS
  601. + Fixed:    Patch #12 [db.c]  (documented here in patch #13)
  602. + Prog:    nnmaster, nn
  603. + Title:    Time zone handling was incomplete and incorrect.
  604. + From:    KFS based on information from many sources
  605. + Fixed:    Patch #13 [pack_date.c]
  606. +     The eastern and western time zones were incorrect.
  607. +     Time zone decoding now knows about "all" time zone formats, e.g.
  608. +     -0800, Z+1, MET DST, UTC, UTC+0300, UT-1, CET
  609. + Prog:    nnmaster, nn
  610. + Title:    Date parsing fail on four digit years and upper case month names
  611. + From:    eggert@twinsun.com (Paul Eggert) + fix
  612. + Fixed:    Patch #13 [pack_date.c]
  613. +     The fixed code will break on two digit years after 2087, but I
  614. +     suppose it leaves some time to find a "complete" fix :-)
  615. + Prog:    nn
  616. + Title:    Should wrap pres.seq. when nn is restarted with the last group read.
  617. + From:    mike@geronimo.pcs.com (Mike Schroeder)
  618. + Fixed:    Patch #13 [nn.c]
  619. + Prog:    nnmaster, nnadmin
  620. + Title:    Should check for errors on GATE file and create with proper modes.
  621. + From:    David Keegel <djk@cs.mu.OZ.AU>
  622. +     Dave Davey <daved@physiol.su.oz.au>
  623. + Fixed:    Patch #13 [proto.c master.c]
  624. + Prog:    nnmaster
  625. + Title:    On some systems nnadmin W will not wakeup master (sleep problem).
  626. + From:    mmitchel@digi.lonestar.org (Mitch Mitchell) + fix (heavily modified)
  627. + Fixed:    Patch #13 [master.c s-template.h]
  628. +     Problem is that sleep() call is not based on SIGALRM, and thus cannot
  629. +     be terminated by that.  The fix provides a replacement for sleep if
  630. +     HAVE_HARD_SLEEP is defined in the system's s- file.
  631. + Prog:    nnacct
  632. + Title:    Accounting data are garbled on SUN4.
  633. + From:    jhb@maths.su.oz.au (John Brownie) + fix
  634. + Fixed:    Patch #13 [s-sunos4-0.h]
  635. +     There is some kind of structure alignment problem on the SUN-4 which
  636. +     may give strange results... Compiling with -misalign fixes this.
  637. + Prog:    nn
  638. + Title:    CR is always mapped to NL on non-TERMIO systems
  639. + From:    david@wraith.cs.uow.edu.au (David E A Wilson) + fix
  640. + Fixed:    Patch #13 [term.c]
  641. + Prog:    nn
  642. + Title:    multi-keys are not reliably recognized via rlogin sessions.
  643. + From:    marius@rhi.hi.is (Marius Olafsson) + fix (not used directly)
  644. + Fixed:    Patch #13 [term.c variable.c nn.1 + several s- files]
  645. +     The basic keyboard handling has been rewritten to make input parsing
  646. +     cleaner and more reliable.  The new code will also preserve partial
  647. +     multi-key sequences for use as normal input (the old code only
  648. +     preserved the first character).  There is also a new variable named
  649. +     "multi-key-guard-time" to control the "between characters" timeout.
  650. + Prog:    nn
  651. + Title:    TCSETAF is broken on pty's on many sysV systems and AIX
  652. + From:    andy@xwkg.icom.com (Andrew H. Marrinson) + fix
  653. +     marius@rhi.hi.is (Marius Olafsson) + fix
  654. + Fixed:    Patch #13 [term.c]
  655. +     When rlogin'ed into some systems, the TCSETAF used to switch to and
  656. +     from raw mode will incorrectly flush OUTPUT as well as input.  The
  657. +     workaround is to use TCSETAW which will not flush input.  This
  658. +     changes the behaviour of nn when using TERMIO and flow-control is
  659. +     set: before nn would flush input after redrawing each menu or article
  660. +     page - this is no longer done (which is probably better anyway!)
  661. + Prog:    nnmaster
  662. + Title:    GROUPS and MASTER files are out of sync
  663. + From:    lupe@alanya.Germany.Sun.COM (Lupe Christoph)
  664. + Fixed:    Patch #13 [db.c global.c master.c]
  665. +     The GROUPS file is now rewritten rather than simply appended to when
  666. +     new groups are added to the database.  I'm not sure this really fixes
  667. +     the problems, but at least it will take care of the situation where
  668. +     the GROUPS file contains some trailing garbage (maybe left over from
  669. +     a system crash).
  670. + Prog:    nn
  671. + Title:    Compiling init.c gives "statement not reached" warnings.
  672. + From:    Tim Evans <tkevans%fallst@wb3ffv.ampr.org>
  673. + Fixed:    Patch #13 [init.c]
  674. + Prog:    nnadmin, nnmaster
  675. + Title:    Problems with GATE file are not handled properly.
  676. + From:    daved@physiol.su.oz.au (Dave Davey)
  677. +     fsb@vitro.uucp (Steve Brailsford)
  678. + Fixed:    Patch #13 [admin.c master.c proto.c]
  679. +     The most noticeable consequence of such problems is that expire is
  680. +     not performed on the database.
  681. + Prog:    nn
  682. + Title:    WRAP variable conflicts with termio on SunOS 4.1 sysV.
  683. + From:    mills@ccu.umanitoba.ca (Gary Mills)
  684. + Fixed:    Patch #13 [term.c term.h]  -- wasn't used, just removed it
  685.   
  686. + Prog:    aux
  687. + Title:    aux script puts /bin in front of PATH.
  688. + From:    barrett@daisy.ee.und.ac.za (Alan P Barrett) + fix
  689. + Fixed:    Patch #13 [aux.sh]
  690.   New features since initial 6.4.0 release
  691.   ----------------------------------------
  692.   
  693. ***************
  694. *** 1770,1773 ****
  695. --- 1884,1935 ----
  696.       4: enter uncond even if no unread.
  697.       If there are no unread articles, nn will actually locate the next
  698.       group in the sequence starting with the remembered group.
  699. +     
  700. + Prog:    nn, nnmaster
  701. + Title:    Improved support for Apollo Domain OS
  702. + From:    mmitchel@digi.lonestar.org (Mitch Mitchell)
  703. +     ianh@bhpmrl.oz.au (Ian Hoyle)
  704. + Added:    Patch #13 [db.c folder.c global.c]
  705. +     Requires new s-apollo.h file which will be included in addendum 1.
  706. + Prog:    nn
  707. + Title:    New "on first-use" construction to allow special actions for first
  708. +     time users of nn (must be placed in global init file).
  709. + From:    KFS on request from Michael Rawdon <rawdon@rex.cs.tulane.edu>
  710. + Added:    Patch #13 [init.c nn.c]
  711. +     
  712. +     on first-use [all]     For all new users of nn (no ~/.nn)
  713. +     on first-use new     For new news readers (no .newsrc)
  714. +     on first-use old     For old news readers (have .newsrc)
  715. +     To avoid adding missing groups to .newsrc on first invocation of nn
  716. +     for a "convert" user, place this in the global init file:
  717. +         on first-use old
  718. +             set new-group-action 0
  719. +         end
  720. + Prog:    nn
  721. + Title:    New integer variable: check-db-update-time.  If non-zero, nn will
  722. +     give a warning check if database has not been updated by nnmaster
  723. +     for the last c-d-u-t hours (default is 12 hours).
  724. + From:    KFS
  725. + Added:    Patch #13 [nn.c]
  726. + Prog:    nn
  727. + Title:    Kill on number of references => new variable: kill-reference-count.
  728. + From:    KFS on request from rolf@sparc1.isgs.uiuc.edu (Rolf Wilson) and
  729. +     poulsen@sp1.csrd.uiuc.edu (David K. Poulsen).
  730. + Added:    Patch #13 [kill.c variable.c]
  731. + Prog:    nn, aux
  732. + Title:    A response can now be interrupted and completed later via h)old cmd.
  733. + From:    KFS
  734. + Added:    Patch #13 [answer.c aux.sh nn.1]
  735. + Prog:    nn, nnpost
  736. + Title:    The hostname put into the mini-inews Path: header can now be
  737. +     configureable via an optional NNTP_PATH_HOSTNAME macro in config.h
  738. + From:    rdavis@convex.com (Ray Davis)
  739. + Added:    Patch #13 [answer.c config.h-dist]
  740.       
  741. *** ./LAST/folder.c    Fri Oct  5 19:07:08 1990
  742. --- folder.c    Fri Nov 16 18:12:03 1990
  743. ***************
  744. *** 178,183 ****
  745. --- 178,186 ----
  746.       }
  747.   
  748.       if (c == '/')
  749. + #ifdef ALLOW_LEADING_DOUBLE_SLASH
  750. +       if (dp != &dest[1])
  751. + #endif
  752.           if (dp != dest && dp[-1] == '/') goto no_parse;
  753.   
  754.        copy:
  755. *** ./LAST/global.c    Wed Nov  7 15:54:29 1990
  756. --- global.c    Mon Dec 10 15:37:07 1990
  757. ***************
  758. *** 453,458 ****
  759. --- 453,467 ----
  760.   }
  761.   
  762.   
  763. + char *substchr(str, c1, c2)
  764. + char *str, c1, c2;
  765. + {
  766. +     char *p;
  767. +     if ((p = strchr(str, c1)) != NULL) *p = c2;
  768. +     return p;
  769. + }
  770.   char *copy_str(str)
  771.   char *str;
  772.   {
  773. ***************
  774. *** 632,637 ****
  775. --- 641,654 ----
  776.       if (may_keep_old == 2) return 3;
  777.       unlink(new);
  778.       return -4;
  779. + }
  780. + save_old_file(name, suffix)
  781. + char *name, *suffix;
  782. + {
  783. +     char buf[FILENAME];
  784. +     sprintf(buf, "%s%s", name, suffix);
  785. +     return move_file(name, buf, 0);
  786.   }
  787.   
  788.   #ifdef HAVE_SYSLOG
  789. *** ./LAST/init.c    Wed Nov  7 15:54:32 1990
  790. --- init.c    Wed Nov 28 20:52:45 1990
  791. ***************
  792. *** 21,26 ****
  793. --- 21,28 ----
  794.   
  795.   export long initial_memory_break;    /* for :debug statistics */
  796.   
  797. + export int first_time_user = 0;
  798.   static int init_err = 0;    /* errors in init file */
  799.   
  800.   
  801. ***************
  802. *** 230,238 ****
  803.    */
  804.   
  805.   static char *sw_string;
  806.   
  807.   #define    SWITCH(str)    \
  808. !     for (sw_string = str; sw_string; sw_string = NULL)
  809.   
  810.   #define CASE(str)    \
  811.       if (strcmp(sw_string, str) == 0)
  812. --- 232,241 ----
  813.    */
  814.   
  815.   static char *sw_string;
  816. + static int sw_loop_once;
  817.   
  818.   #define    SWITCH(str)    \
  819. !     for (sw_string = str, sw_loop_once = 1; --sw_loop_once == 0; )
  820.   
  821.   #define CASE(str)    \
  822.       if (strcmp(sw_string, str) == 0)
  823. ***************
  824. *** 909,914 ****
  825. --- 912,931 ----
  826.   
  827.           start_up_macro = parse_enter_macro(f, NL);
  828.           return;
  829. +     }
  830. +     CASE( "first-use" ) { 
  831. +         extern char *newsrc_file;
  832. +         if (!first_time_user) break;
  833. +         if (argv(2) == NULL || ARG(2, "all")) return;
  834. +         if (newsrc_file == NULL) /* == code from visit_rc_file == */
  835. +         newsrc_file = home_relative(".newsrc");
  836. +         if (ARG(2, "old") && file_exist(newsrc_file, (char *)NULL))
  837. +         return;
  838. +         if (ARG(2, "new") && !file_exist(newsrc_file, (char *)NULL))
  839. +         return;
  840. +         break;
  841.       }
  842.   
  843.       goto on_err;
  844. *** ./LAST/kill.c    Tue Sep 18 12:45:00 1990
  845. --- kill.c    Mon Nov 26 15:48:27 1990
  846. ***************
  847. *** 12,17 ****
  848. --- 12,18 ----
  849.   export int dflt_kill_select = 30;
  850.   export int kill_file_loaded = 0;
  851.   export int kill_debug = 0;
  852. + export int kill_ref_count = 0;
  853.   
  854.   char KILL_FILE[] =     "kill";
  855.   char COMPILED_KILL[] =    "KILL.COMP";
  856. ***************
  857. *** 217,224 ****
  858.       if (kl->kill_flag & AUTO_KILL)
  859.           goto did_kill;
  860.   
  861. !     if (kl->kill_flag & AUTO_SELECT)
  862.           ah->attr = A_AUTO_SELECT;
  863.       goto no_kill;
  864.       }
  865.   
  866. --- 218,227 ----
  867.       if (kl->kill_flag & AUTO_KILL)
  868.           goto did_kill;
  869.   
  870. !     if (kl->kill_flag & AUTO_SELECT) {
  871.           ah->attr = A_AUTO_SELECT;
  872. +         goto did_select;
  873. +     }
  874.       goto no_kill;
  875.       }
  876.   
  877. ***************
  878. *** 225,230 ****
  879. --- 228,243 ----
  880.       if (unless_match) goto did_kill;
  881.   
  882.    no_kill:
  883. +     if (kill_ref_count && (ah->replies & 0x7f) >= kill_ref_count) {
  884. +     if (kill_debug) {
  885. +         pg_next();
  886. +         printf("REFERENCE COUNT (%d) >= %d\n",
  887. +            ah->replies & 0x7f, kill_ref_count);
  888. +     }
  889. +     goto did_kill;
  890. +     }
  891. +  did_select:
  892.       if (kill_debug && pg_end() < 0) kill_debug = 0;
  893.       return 0;
  894.   
  895. *** ./LAST/man/nn.1.B    Wed Nov  7 15:54:38 1990
  896. --- man/nn.1.B    Wed Feb  6 15:33:34 1991
  897. ***************
  898. *** 211,217 ****
  899.   just \fBreturn\fP to take the default action):
  900.   .br
  901.   .sp 0.5v
  902. !     a)bort c)c e)dit i)spell m)ail r)eedit s)end v)iew w)rite
  903.   .br
  904.       Action: (post article)
  905.   .sp 0.5v
  906. --- 211,217 ----
  907.   just \fBreturn\fP to take the default action):
  908.   .br
  909.   .sp 0.5v
  910. !     a)bort c)c e)dit h)old i)spell m)ail r)eedit s)end v)iew w)rite
  911.   .br
  912.       Action: (post article)
  913.   .sp 0.5v
  914. ***************
  915. *** 227,232 ****
  916. --- 227,234 ----
  917.   .br
  918.   \fBe\fP    edit the file again,
  919.   .br
  920. + \fBh\fP    hold response for later completion,
  921. + .br
  922.   \fBi\fP    run an (interactive) \fBspell-checker\fP on the text,
  923.   .br
  924.   \fBm\fP    mail a (blind) copy to a specified recipient,
  925. ***************
  926. *** 246,251 ****
  927. --- 248,260 ----
  928.   \fBy\fP    confirm \fIdefault answer\fP (e.g. \fIyes\fP post it)
  929.   .in -2m
  930.   .DT
  931. + .LP
  932. + To complete an unfinished response saved by the h)old command, simply
  933. + enter any response action, e.g. \fBR\fP {\fBreply\fP}.  This will
  934. + notice the unfinished response and ask you whether you want to
  935. + complete it now.  Only one unfinished response can exist at a time.
  936. + Notice that the $A environment variable may no longer be valid as a
  937. + path to the original article when the response is completed.
  938.   .LP
  939.   \fBRelated variables\fP:
  940.   append-signature-mail, append-signature-post, default-distribution,
  941. *** ./LAST/man/nn.1.C    Wed Nov  7 15:54:41 1990
  942. --- man/nn.1.C    Wed Feb  6 15:33:34 1991
  943. ***************
  944. *** 681,686 ****
  945. --- 681,694 ----
  946.   The key which deletes the current line
  947.   when \fInn\fP is prompting for a string, e.g. a file name.
  948.   .TP
  949. + \fBkill-reference-count\fP \fIN\fP    (integer, default 0)
  950. + When this variable is non-zero, all articles which have \fIN\fP or
  951. + more references on the References: line (corresponding to the number
  952. + of >>'s on the menu line) will be auto-killed if they are not
  953. + auto-selected (or preserved) via an entry in the kill file.  It should
  954. + probably not be used globally for all groups, but can be set on a
  955. + per-group via the entry macros.
  956. + .TP
  957.   \fBlayout\fP \fInumber\fP    (integer, default 1)
  958.   Set the menu layout.  The argument must be a number between 0 and 4.
  959.   .TP
  960. ***************
  961. *** 815,820 ****
  962. --- 823,841 ----
  963.   start-up if it has changed since it was last shown.  The message is
  964.   taken from the file "motd" in the lib directory.  It can also be shown
  965.   (again) using the \fB:motd\fP command.
  966. + .TP
  967. + \fBmulti-key-guard-time\fP \fItimeout\fP    (integer, default 2)
  968. + When reading a multi-key sequence from the keyboard, \fInn\fP will
  969. + expect the characters constituting the multi-key to arrive "quickly"
  970. + after each other.  When a partial multi-key sequence is read,
  971. + \fInn\fP will wait (at least) \fItimeout\fP tenths of a second for
  972. + each of the following characters to arrive to complete the multi-key
  973. + sequence.  If the multi-key sequence is \fInot\fP completed within
  974. + this period, \fInn\fP will read the partial multi-key sequence as
  975. + individual characters instead.  This way it is still possible to use
  976. + for example the ESC key on a terminal with vt100 like arrow keys.
  977. + When \fInn\fP is used via an rlogin connection, you may have to
  978. + increase the timeout to get reliable recognition of multi-keys.
  979.   .TP
  980.   \fBnew-group-action\fP \fIaction\fP    (integer, default 3)
  981.   This variable controls how new groups are treated by \fInn\fP.  It is
  982. *** ./LAST/master.c    Wed Nov  7 15:54:46 1990
  983. --- master.c    Mon Dec 10 17:04:08 1990
  984. ***************
  985. *** 287,293 ****
  986.       gh->group_num = master.number_of_groups++;
  987.       gh->creation_time = cur_time();
  988.   
  989. !     db_append_group(gh);
  990.   
  991.       group_restriction(gh);    /* done after append to avoid setting ! */
  992.       clean_group(gh);
  993. --- 287,293 ----
  994.       gh->group_num = master.number_of_groups++;
  995.       gh->creation_time = cur_time();
  996.   
  997. !     db_rewrite_groups(1, (group_header *)NULL);
  998.   
  999.       group_restriction(gh);    /* done after append to avoid setting ! */
  1000.       clean_group(gh);
  1001. ***************
  1002. *** 335,340 ****
  1003. --- 335,341 ----
  1004.       char command[512];
  1005.       char groupname[512];
  1006.       group_header *groups, *next_g, *gh;
  1007. +     group_header *dupg;
  1008.       FILE *src;
  1009.       int lcount, use_group_file, found_nn_group = 0;
  1010.   
  1011. ***************
  1012. *** 440,445 ****
  1013. --- 441,453 ----
  1014.           gh->archive_file = NULL;
  1015.       }
  1016.   
  1017. +     for (dupg = groups->next_group; dupg != NULL; dupg = dupg->next_group)
  1018. +         if (strcmp(dupg->group_name, gh->group_name) == 0) break;
  1019. +     if (dupg != NULL) {
  1020. +         printf("Ignored duplicate of group %s\n", dupg->group_name);
  1021. +         continue;
  1022. +     }
  1023.       gh->group_num = master.number_of_groups++;
  1024.   
  1025.       if (trace || debug_mode)
  1026. ***************
  1027. *** 471,487 ****
  1028.   
  1029.       printf("%s %s/GROUPS file\n",
  1030.          use_group_file ? "Updating" : "Building", db_directory);
  1031. -     sprintf(command, "cd %s ; [ -f GROUPS ] && (rm -f GROUPS~ ; mv GROUPS GROUPS~)",
  1032. -         db_directory);
  1033. -     system(command);
  1034.   
  1035. !     open_groups(OPEN_CREATE|MUST_EXIST);
  1036. !     for (gh = groups->next_group; gh != NULL; gh = gh->next_group)
  1037. !     db_append_group(gh);
  1038.   
  1039. -     close_groups();
  1040.       if (initialize > 0) {
  1041.       printf("Setting articles per group limit to %d...\n", initialize);
  1042.       db_write_master();
  1043. --- 479,487 ----
  1044.   
  1045.       printf("%s %s/GROUPS file\n",
  1046.          use_group_file ? "Updating" : "Building", db_directory);
  1047.   
  1048. !     db_rewrite_groups(use_group_file, groups);
  1049.   
  1050.       if (initialize > 0) {
  1051.       printf("Setting articles per group limit to %d...\n", initialize);
  1052.       db_write_master();
  1053. ***************
  1054. *** 547,552 ****
  1055. --- 547,581 ----
  1056.       log_entry('M', "Reread GROUPS file");
  1057.   }
  1058.   
  1059. + #ifdef HAVE_HARD_SLEEP
  1060. + /*
  1061. +  * Hard sleeper...  The normal sleep is not terminated by SIGALRM or
  1062. +  * other signals which nnadmin may send to wake it up.
  1063. +  */
  1064. + static int got_alarm;
  1065. + static sig_type catch_alarm()
  1066. + {
  1067. +     signal(SIGALRM, SIG_IGN);
  1068. +     got_alarm = 1;
  1069. + }
  1070. +     
  1071. + static take_a_nap(t)
  1072. + int t;
  1073. + {
  1074. +     got_alarm = 0;
  1075. +     signal(SIGALRM, catch_alarm);
  1076. +     alarm(repeat_delay);
  1077. +     /* the timeout is at least 1 minute, so we ignore racing condition here */
  1078. +     pause();
  1079. +     if (!got_alarm) {
  1080. +     signal(SIGALRM, SIG_IGN);
  1081. +     alarm(0);
  1082. +     }
  1083. + }
  1084. + #else
  1085. + #define take_a_nap(t) sleep(t)
  1086. + #endif
  1087.   
  1088.   main(argc, argv)
  1089.   int argc;
  1090. ***************
  1091. *** 557,562 ****
  1092. --- 586,592 ----
  1093.       int group_selection;
  1094.       int temp;
  1095.       int skip_pass;
  1096. +     long pass_no;
  1097.   
  1098.       umask(002);            /* avoid paranoia */
  1099.   
  1100. ***************
  1101. *** 623,628 ****
  1102. --- 653,662 ----
  1103.       }
  1104.   
  1105.       if (proto_lock(I_AM_MASTER, PL_SET) != 0) {
  1106. +     extern char proto_host[];
  1107. +     if (proto_host[0])
  1108. +         printf("The master is running on another host (%s)\n", proto_host);
  1109. +     else
  1110.       printf("The master is already running\n");
  1111.       exit(0);
  1112.       }
  1113. ***************
  1114. *** 710,716 ****
  1115.       unconditional = 1;
  1116.       }
  1117.   
  1118. !     for (;;) {
  1119.   #ifdef NNTP
  1120.       if (use_nntp && nntp_get_active() < 0) {
  1121.           nntp_close_server();
  1122. --- 744,755 ----
  1123.       unconditional = 1;
  1124.       }
  1125.   
  1126. !     for (pass_no = 0; !s_hangup; pass_no++) {
  1127. !     if (pass_no > 0) {
  1128. !         take_a_nap(repeat_delay);
  1129. !         if (s_hangup) break;
  1130. !     }
  1131.   #ifdef NNTP
  1132.       if (use_nntp && nntp_get_active() < 0) {
  1133.           nntp_close_server();
  1134. ***************
  1135. *** 719,725 ****
  1136.                 repeat_delay ? "sleeping" : "terminating");
  1137.           if (repeat_delay == 0)
  1138.           nn_exit(1);
  1139. -         sleep(repeat_delay);
  1140.           continue;
  1141.       }
  1142.   #endif
  1143. --- 758,763 ----
  1144. ***************
  1145. *** 753,760 ****
  1146.           }
  1147.   
  1148.           if (trace) log_entry('T', "none");
  1149. -         sleep(repeat_delay);
  1150. -         if (s_hangup) break;
  1151.           continue;
  1152.       }
  1153.   
  1154. --- 791,796 ----
  1155. ***************
  1156. *** 772,779 ****
  1157.   #ifdef NNTP
  1158.       if (use_nntp) nntp_cleanup();
  1159.   #endif
  1160. -     sleep(repeat_delay);
  1161. -     if (s_hangup) break;
  1162.       }
  1163.   
  1164.       nn_exit(0);
  1165. --- 808,813 ----
  1166. ***************
  1167. *** 794,801 ****
  1168.       int32 arg;
  1169.       int must_collect;
  1170.       register group_header *gh;
  1171.   
  1172. !     gate = open_file(relative(master_directory, "GATE"), OPEN_READ | OPEN_UNLINK);
  1173.       if (gate == NULL) return 0;
  1174.   
  1175.       sleep(2);    /* give administrator time to flush buffers */
  1176. --- 828,836 ----
  1177.       int32 arg;
  1178.       int must_collect;
  1179.       register group_header *gh;
  1180. +     FILE *open_gate_file();
  1181.   
  1182. !     gate = open_gate_file(OPEN_READ);
  1183.       if (gate == NULL) return 0;
  1184.   
  1185.       sleep(2);    /* give administrator time to flush buffers */
  1186. *** ./LAST/nn.c    Wed Nov  7 15:54:53 1990
  1187. --- nn.c    Wed Jan 30 18:32:14 1991
  1188. ***************
  1189. *** 46,51 ****
  1190. --- 46,53 ----
  1191.       verbose = 0,
  1192.       Debug = 0;
  1193.   
  1194. + export int check_db_update = 12 /* HOURS */;
  1195.   static int
  1196.       nngrab_mode = 0,
  1197.       prompt_for_group = 0;
  1198. ***************
  1199. *** 121,128 ****
  1200.       return 0;        /* will not update .newsrc */
  1201.       }
  1202.   
  1203. !     if (proto_lock(I_AM_NN, PL_SET))
  1204.       user_error("\nAnother nn process is already running\n\n");
  1205.   
  1206.       must_unlock = 1;
  1207.       return 0;
  1208. --- 123,136 ----
  1209.       return 0;        /* will not update .newsrc */
  1210.       }
  1211.   
  1212. !     if (proto_lock(I_AM_NN, PL_SET)) {
  1213. !     extern char proto_host[];
  1214. !     
  1215. !     if (proto_host[0])
  1216. !         user_error("\nnn is running on host %s\nor .nn/LOCK should be removed.\n\n", proto_host);
  1217. !     else
  1218.       user_error("\nAnother nn process is already running\n\n");
  1219. +     }
  1220.   
  1221.       must_unlock = 1;
  1222.       return 0;
  1223. ***************
  1224. *** 223,228 ****
  1225. --- 231,237 ----
  1226.   
  1227.       if (access_mode == 0 && !also_read_articles) {
  1228.       gh = last_group_maint(gh, 0);
  1229. +     did_jump = gh != group_sequence;
  1230.       m_invoke(-2);
  1231.       }
  1232.   
  1233. ***************
  1234. *** 638,643 ****
  1235. --- 647,667 ----
  1236.       return 1;
  1237.   }
  1238.   
  1239. + static do_db_check()
  1240. + {
  1241. +     import char *news_active;
  1242. +     time_t last_upd;
  1243. +     last_upd = (cur_time() - master.last_scan) / (60 * 60);
  1244. +     if (last_upd < check_db_update) return;
  1245. +     /* too old - but is nnmaster the culprit? */
  1246. +     if (master.last_scan == file_exist(news_active, (char *)NULL))
  1247. +     printf("Notice: no news has arrived for the last %ld hours\n", last_upd);
  1248. +     else
  1249. +     printf("Notice: nnmaster has not updated database in %ld hours\n", last_upd);
  1250. +     sleep(3);
  1251. + }
  1252.   clean_group(gh)
  1253.   group_header *gh;
  1254.   {
  1255. ***************
  1256. *** 768,773 ****
  1257. --- 792,800 ----
  1258.       init_term(1);
  1259.   
  1260.       if (say_welcome) {
  1261. +         extern int first_time_user;
  1262. +         
  1263. +         first_time_user = 1;
  1264.           display_file("adm.welcome", CLEAR_DISPLAY | CONFIRMATION);
  1265.           clrdisp();
  1266.       }
  1267. ***************
  1268. *** 929,934 ****
  1269. --- 956,964 ----
  1270.       break;
  1271.   
  1272.        case I_AM_NN:
  1273. +     if (check_db_update)
  1274. +         do_db_check();
  1275.       if (unread_articles == 0 &&
  1276.           group_name_args == 0 &&
  1277.           !also_read_articles &&
  1278. *** ./LAST/pack_date.c    Mon Apr 23 18:25:59 1990
  1279. --- pack_date.c    Tue Feb  5 17:50:18 1991
  1280. ***************
  1281. *** 17,22 ****
  1282. --- 17,200 ----
  1283.   
  1284.   /* #define DATE_TEST /* never define this !! */
  1285.   
  1286. + #ifndef USE_OLD_TZ_CODE
  1287. + #undef W
  1288. + #undef E
  1289. + #undef DST
  1290. + #undef UTC
  1291. + #define W    * (-60) - 
  1292. + #define E    * 60 +
  1293. + #define DST    + 60
  1294. + #define UTC    60 *
  1295. + static struct zonetab {
  1296. +     char *tz_name;
  1297. +     int32 tz_offset;
  1298. + } ztab[] = {
  1299. +     "a",    UTC 1,        /* UTC+1h */
  1300. +     "acsst",    9 E 30 DST,    /* Cent. Australia */
  1301. +     "acst",    9 E 30,        /* Cent. Australia */
  1302. +     "adt",    4 W 0 DST,    /* Atlantic (Canada) */
  1303. +     "aesst",    10 E 0 DST,    /* E. Australia */
  1304. +     "aest",    10 E 0,        /* E. Australia */
  1305. +     "ast",    4 W 0,        /* Atlantic (Canada) */
  1306. +     "awsst",    8 E 0 DST,    /* W. Australia */
  1307. +     "awst",    8 E 0,        /* W. Australia */
  1308. +     "b",    UTC 2,        /* UTC+2h */
  1309. +     "bst",    0 E 0 DST,    /* Great Britain summertime */
  1310. +     "c",    UTC 3,        /* UTC+3h */
  1311. +     "cdt",    6 W 0 DST,    /* Central */
  1312. +     "cest",    1 E 0 DST,    /* Central Europe */
  1313. +     "cet",    1 E 0,        /* Central Europe */
  1314. +     "cetdst",    1 E 0 DST,    /* Central Europe */
  1315. +     "cst",    6 W 0,        /* Central */
  1316. +     "d",    UTC 4,        /* UTC+4h */
  1317. +     "dnt",    1 E 0,        /* Denmark */
  1318. +     "dst",    1 E 0 DST,    /* Denmark */
  1319. +     "e",    UTC 5,        /* UTC+5h */
  1320. +     "edt",    5 W 0 DST,    /* Eastern US */
  1321. +     "eest",    2 E 0 DST,    /* Eastern Europe */
  1322. +     "eet",    2 E 0,        /* Eastern Europe */
  1323. +     "eetdst",    2 E 0 DST,    /* Eastern Europe */
  1324. +     "est",    5 W 0,        /* Eastern US */
  1325. +     "f",    UTC 6,        /* UTC+6h */
  1326. +     "g",    UTC 7,        /* UTC+7h */
  1327. +     "gmt",    0,        /*  */
  1328. +     "h",    UTC 8,        /* UTC+8h */
  1329. +     "hdt",    10 W 0 DST,    /* Hawaii/Alaska */
  1330. +     "hst",    10 W 0,        /* Hawaii/Alaska */
  1331. +     "i",    UTC 9,        /* UTC+9h */
  1332. +     "ist",    2 E 0,        /* Israel */
  1333. +     "jst",    9 E 0,        /* Japan */
  1334. +     "k",    UTC 10,        /* UTC+10h */
  1335. +     "l",    UTC 11,        /* UTC+11h */
  1336. +     "m",    UTC 12,        /* UTC+12h */
  1337. +     "mdt",    7 W 0 DST,    /* Mountain US */
  1338. +     "mest",    1 E 0 DST,    /* Central Europe */
  1339. +     "met",    1 E 0,        /* Central Europe */
  1340. +     "metdst",    1 E 0 DST,    /* Central Europe */
  1341. +     "mst",    7 W 0,        /* Mountain */
  1342. +     "n",    UTC -1,        /* UTC-1h */
  1343. +     "ndt",    3 W 30 DST,    /* Nfld. (Canada) */
  1344. +     "nst",    3 W 30,        /* Nfld. (Canada) */
  1345. +     "o",    UTC -2,        /* UTC-2h */
  1346. +     "p",    UTC -3,        /* UTC-3h */
  1347. +     "pdt",    8 W 0 DST,    /* Pacific */
  1348. +     "pst",    8 W 0,        /* Pacific */
  1349. +     "q",    UTC -4,        /* UTC-4h */
  1350. +     "r",    UTC -5,        /* UTC-5h */
  1351. +     "s",    UTC -6,        /* UTC-6h */
  1352. +     "t",    UTC -7,        /* UTC-7h */
  1353. +     "u",    UTC -8,        /* UTC-8h */
  1354. +     "ut",    UTC 0,        /* UTC */
  1355. +     "utc",    UTC 0,        /* UTC */
  1356. +     "v",    UTC -9,        /* UTC-9h */
  1357. +     "w",    UTC -10,    /* UTC-10h */
  1358. +     "west",    0 E 0 DST,    /* Western Europe */
  1359. +     "wet",    0 E 0,        /* Western Europe */
  1360. +     "wetdst",    0 E 0 DST,    /* Western Europe */
  1361. +     "x",    UTC -11,    /* UTC-11h */
  1362. +     "y",    UTC -12,    /* UTC-12h */
  1363. +     "ydt",    9 W 0 DST,    /* Yukon */
  1364. +     "yst",    9 W 0,        /* Yukon */
  1365. +     "z",    UTC 0,        /* UTC */
  1366. +     NULL,    0
  1367. + };
  1368. + #undef MAXZ
  1369. + #define MAXZ    10
  1370. + static long tzone(date)
  1371. + register char *date;
  1372. + {
  1373. +     register int i, n;
  1374. +     static char zone[MAXZ], num[MAXZ];
  1375. +     register struct zonetab *z;
  1376. +     long adjust, sign;
  1377. +     static int first = 1;
  1378. +     i = 0;
  1379. +     while (*date && isascii(*date) && isspace(*date)) date++;
  1380. +     
  1381. +     for ( ; *date && isascii(*date) ; date++) {
  1382. +     if (*date == '+' || *date == '-' || isdigit(*date))
  1383. +         goto numeric_zone;
  1384. +     if (isspace(*date)) break;
  1385. +     if (!isalpha(*date)) continue;    /* p.s.t. -> pst */
  1386. +     if (i == MAXZ) continue;
  1387. +     zone[i++] = isupper(*date) ? tolower(*date) : *date;
  1388. +     }
  1389. +     while (*date && isascii(*date) && isspace(*date)) date++;
  1390. +     if (*date && i < MAXZ-3) {
  1391. +     if (date[0] != 'D' && date[0] != 'd') goto no_dst;
  1392. +     if (date[1] != 'S' && date[1] != 's') goto no_dst;
  1393. +     if (date[2] != 'T' && date[2] != 't') goto no_dst;
  1394. +     zone[i++] = 'd';
  1395. +     zone[i++] = 's';
  1396. +     zone[i++] = 't';
  1397. +     }
  1398. +  no_dst:
  1399. +     if (i == 0) return 0;
  1400. +     adjust = 0;
  1401. +     if (*date != '+' && *date != '-') goto non_numeric;
  1402. +  numeric_zone:            /* {+-}[H]H[MM] */
  1403. +     switch (*date) {
  1404. +      case '-':
  1405. +     date++;
  1406. +     sign = -1;
  1407. +     break;
  1408. +      case '+':
  1409. +     date++;
  1410. +      default:
  1411. +     sign = 1;
  1412. +     break;
  1413. +     }
  1414. +     adjust = 0;
  1415. +     for (n = 0; n < MAXZ && *date && isascii(*date) && isdigit(*date); )
  1416. +     num[n++] = *date++;
  1417. +     num[n] = NUL;
  1418. +     switch (n) {
  1419. +      case 0:
  1420. +     break;
  1421. +      case 3:    /* +HMM */
  1422. +     adjust = atoi(num+1);
  1423. +      case 1:    /* +H */
  1424. +     adjust += (num[0] - '0') * 60;
  1425. +     break;
  1426. +      case 2:    /* +HH */
  1427. +     adjust = atoi(num) * 60;
  1428. +     break;
  1429. +      default:    /* +HHMM */
  1430. +     if (num[2] != '0' || num[3] != '0') {
  1431. +         num[4] = NUL;
  1432. +         adjust = atoi(num + 2);
  1433. +     }
  1434. +     num[2] = NUL;
  1435. +     adjust += atoi(num) * 60;
  1436. +     break;
  1437. +     }
  1438. +     adjust *= sign;
  1439. +     if (i == 0) return adjust;
  1440. +  non_numeric:
  1441. +     zone[i] = NUL;
  1442. +     for (z = ztab; z->tz_name != NULL; z++) {
  1443. +     if ((i = strcmp(zone, z->tz_name)) > 0) continue;
  1444. +     if (i < 0) break;
  1445. +     return z->tz_offset + adjust;
  1446. +     }
  1447. +     return adjust;
  1448. + }
  1449. + #else
  1450.   static long wtz(h, m, c)
  1451.   int  h, m;
  1452.   char c;
  1453. ***************
  1454. *** 98,103 ****
  1455. --- 276,283 ----
  1456.       return tz;
  1457.   }
  1458.   
  1459. + #endif
  1460.   static next_int(dp)
  1461.   char **dp;
  1462.   {
  1463. ***************
  1464. *** 124,149 ****
  1465.   
  1466.       while (*date && isspace(*date)) date++;
  1467.   
  1468. !     switch (*date++) {
  1469. !      case 'J':
  1470. !     if (*date++ == 'a') { mon = 0; break; }
  1471. !     if (*date++ == 'n') { mon = 5; break; }
  1472.       mon = 6; break;
  1473. !      case 'F':
  1474.       mon = 1; break;
  1475. !      case 'M':
  1476. !     if (*++date == 'r') { mon = 2; break; }
  1477.       mon = 4; break;
  1478. !      case 'A':
  1479. !     if (*date++ == 'p') { mon = 3; break; }
  1480.       mon = 7; break;
  1481. !      case 'S':
  1482.       mon = 8; break;
  1483. !      case 'O':
  1484.       mon = 9; break;
  1485. !      case 'N':
  1486.       mon = 10; break;
  1487. !      case 'D':
  1488.       mon = 11; break;
  1489.        default:
  1490.       return 0;
  1491. --- 304,330 ----
  1492.   
  1493.       while (*date && isspace(*date)) date++;
  1494.   
  1495. !     if (date[0] == NUL || date[1] == NUL || date[2] == NUL) return 0;
  1496. !     switch (date[0]) {
  1497. !      case 'J': case 'j':
  1498. !     if (date[1] == 'a' || date[1] == 'A') { mon = 0; break; }
  1499. !     if (date[2] == 'n' || date[2] == 'N') { mon = 5; break; }
  1500.       mon = 6; break;
  1501. !      case 'F': case 'f':
  1502.       mon = 1; break;
  1503. !      case 'M': case 'm':
  1504. !     if (date[2] == 'r' || date[2] == 'R') { mon = 2; break; }
  1505.       mon = 4; break;
  1506. !      case 'A': case 'a':
  1507. !     if (date[1] == 'p' || date[1] == 'P') { mon = 3; break; }
  1508.       mon = 7; break;
  1509. !      case 'S': case 's':
  1510.       mon = 8; break;
  1511. !      case 'O': case 'o':
  1512.       mon = 9; break;
  1513. !      case 'N': case 'n':
  1514.       mon = 10; break;
  1515. !      case 'D': case 'd':
  1516.       mon = 11; break;
  1517.        default:
  1518.       return 0;
  1519. ***************
  1520. *** 152,158 ****
  1521. --- 333,341 ----
  1522.       year = next_int(&date);
  1523.       hour = next_int(&date);
  1524.       min = next_int(&date);
  1525. +     if (*date == ':') next_int(&date);
  1526.   
  1527. +     if (year >= 100) year -= 1900;    /* xxYY -> YY */
  1528.       year -= 87;    /* base is 1987 */
  1529.       if (year < 0) year += 100;
  1530.   
  1531. *** ./LAST/patchlevel.h    Wed Nov  7 15:54:55 1990
  1532. --- patchlevel.h    Tue Feb  5 15:20:42 1991
  1533. ***************
  1534. *** 23,29 ****
  1535.    *    1990-09-18: Patch #10 (6.4.10) - HIGH
  1536.    *    1990-10-05: Patch #11 (6.4.11) - HIGH
  1537.    *    1990-11-07: Patch #12 (6.4.12) - LOW
  1538.    */
  1539.   
  1540. ! #define PATCHLEVEL 12
  1541.   
  1542. --- 23,30 ----
  1543.    *    1990-09-18: Patch #10 (6.4.10) - HIGH
  1544.    *    1990-10-05: Patch #11 (6.4.11) - HIGH
  1545.    *    1990-11-07: Patch #12 (6.4.12) - LOW
  1546. +  *    1991-02-06: Patch #13 (6.4.13) - MEDIUM
  1547.    */
  1548.   
  1549. ! #define PATCHLEVEL 13
  1550.   
  1551. *** ./LAST/proto.c    Mon Jul  9 18:00:05 1990
  1552. --- proto.c    Mon Dec 10 16:26:32 1990
  1553. ***************
  1554. *** 18,23 ****
  1555. --- 18,26 ----
  1556.   
  1557.   import char *master_directory, *db_directory;
  1558.   
  1559. + #define HOSTBUF 80
  1560. + export char proto_host[HOSTBUF];    /* host having the lock */
  1561.   /*
  1562.    *    When setting a lock, we must check a little later that
  1563.    *    we really got the lock set, i.e. that another process
  1564. ***************
  1565. *** 38,43 ****
  1566. --- 41,88 ----
  1567.    *    pid    Locked and running (PL_CHECK)
  1568.    */
  1569.   
  1570. + static write_lock(lock, operation)
  1571. + char *lock, *operation;
  1572. + {
  1573. +     FILE *m_pid;
  1574. +     char host[HOSTBUF];
  1575. +     m_pid = open_file(lock, OPEN_CREATE);
  1576. +     if (m_pid == NULL)
  1577. +     sys_error("Cannot %s lock file: %s", operation, lock);
  1578. +     gethostname(host, HOSTBUF);
  1579. +     fprintf(m_pid, "%d\n%s\n", process_id, host);
  1580. +     fclose(m_pid);
  1581. + }
  1582. + static int read_lock(lock)
  1583. + char *lock;
  1584. + {
  1585. +     FILE *m_pid;
  1586. +     char host[HOSTBUF];
  1587. +     char pid[10];
  1588. +     
  1589. +     pid[0] = NUL;
  1590. +     proto_host[0] = NUL;
  1591. +     
  1592. +     m_pid = open_file(lock, OPEN_READ);
  1593. +     if (m_pid == NULL) return -2;    /* no lock */
  1594. +     fgets(pid, 10, m_pid);
  1595. +     fgets(proto_host, HOSTBUF, m_pid);
  1596. +     fclose(m_pid);
  1597. +     if (pid[0] == NUL) return 0;    /* corrupted lock */
  1598. +     
  1599. +     if (proto_host[0] != NUL) {
  1600. +     substchr(proto_host, NL, NUL);
  1601. +     gethostname(host, HOSTBUF);
  1602. +     if (strncmp(proto_host, host, HOSTBUF) != 0)
  1603. +         return -1;            /* locked by another host */
  1604. +     proto_host[0] = NUL;
  1605. +     }
  1606. +     return atoi(pid);
  1607. + }
  1608.   proto_lock(prog, command)
  1609.   {
  1610.       FILE *m_pid;
  1611. ***************
  1612. *** 65,73 ****
  1613.       }
  1614.   
  1615.       if (command == PL_TRANSFER) {
  1616. !     m_pid = open_file(lock, OPEN_UPDATE|MUST_EXIST);
  1617. !     fprintf(m_pid, "%d\n", process_id);
  1618. !     fclose(m_pid);
  1619.       return 1;
  1620.       }
  1621.   
  1622. --- 110,116 ----
  1623.       }
  1624.   
  1625.       if (command == PL_TRANSFER) {
  1626. !     write_lock(lock, "transfer");
  1627.       return 1;
  1628.       }
  1629.   
  1630. ***************
  1631. *** 77,94 ****
  1632.       try = 1;
  1633.    again:
  1634.   
  1635. !     m_pid = open_file(lock, OPEN_READ);
  1636. !     if (m_pid == NULL) goto no_lock;
  1637. !     any = fgets(buf, 10, m_pid);
  1638. !     fclose(m_pid);
  1639. !     if (any == NULL || (pid = atoi(buf)) <= 2) {
  1640. !     /* lock file is corrupted! */
  1641.       if (who_am_i == I_AM_NN) goto rm_lock;
  1642.       if (--try < 0) goto rm_lock;
  1643.       sleep(LOCK_SAFETY);    /* maybe it is being written */
  1644.       goto again;
  1645. !     }
  1646.   
  1647.       if (kill(pid, command == PL_TERMINATE ? SIGHUP : SIGALRM) == 0) {
  1648.       switch (command) {
  1649. --- 120,140 ----
  1650.       try = 1;
  1651.    again:
  1652.   
  1653. !     switch (pid = read_lock(lock)) {
  1654. !      case -2:
  1655. !     goto no_lock;
  1656. !      case -1:            /* wrong host */
  1657. !     return 1;
  1658. !      case 0:
  1659. !      case 1:
  1660. !      case 2:            /* corrupted lock file */
  1661.       if (who_am_i == I_AM_NN) goto rm_lock;
  1662.       if (--try < 0) goto rm_lock;
  1663.       sleep(LOCK_SAFETY);    /* maybe it is being written */
  1664.       goto again;
  1665. !      default:
  1666. !     break;
  1667. !     }    
  1668.   
  1669.       if (kill(pid, command == PL_TERMINATE ? SIGHUP : SIGALRM) == 0) {
  1670.       switch (command) {
  1671. ***************
  1672. *** 124,134 ****
  1673.       if (command != PL_SET && command != PL_SET_QUICK && command != PL_SET_WAIT)
  1674.       return -1;
  1675.   
  1676. !     m_pid = open_file(lock, OPEN_CREATE);
  1677. !     if (m_pid == NULL)
  1678. !     sys_error("Cannot create lock file: %s", lock);
  1679. !     fprintf(m_pid, "%d\n", process_id);
  1680. !     fclose(m_pid);
  1681.   
  1682.       /* a user will not start nn twice at the exact same time! */
  1683.       if (who_am_i == I_AM_NN || command == PL_SET_QUICK) return 0;
  1684. --- 170,176 ----
  1685.       if (command != PL_SET && command != PL_SET_QUICK && command != PL_SET_WAIT)
  1686.       return -1;
  1687.   
  1688. !     write_lock(lock, "create");
  1689.   
  1690.       /* a user will not start nn twice at the exact same time! */
  1691.       if (who_am_i == I_AM_NN || command == PL_SET_QUICK) return 0;
  1692. ***************
  1693. *** 135,148 ****
  1694.   
  1695.       sleep(LOCK_SAFETY);
  1696.   
  1697. !     m_pid = open_file(lock, OPEN_READ);
  1698. !     if (m_pid == NULL) return 1; /* somebody stole the lock file */
  1699. !     any = fgets(buf, 10, m_pid);
  1700. !     fclose(m_pid);
  1701.   
  1702. !     if (any == NULL || atoi(buf) != process_id) return 1;
  1703.   
  1704. !     return 0;    /* lock is set */
  1705.   }
  1706.   
  1707.   send_master(command, gh, opt, arg)
  1708. --- 177,219 ----
  1709.   
  1710.       sleep(LOCK_SAFETY);
  1711.   
  1712. !     if (read_lock(lock) != process_id)
  1713. !     return 1;    /* somebody stole the lock file */
  1714. !     return 0;     /* lock is set */
  1715. ! }
  1716. ! FILE *open_gate_file(mode)
  1717. ! int mode;
  1718. ! {
  1719. !     char *gate, *err;
  1720. !     FILE *gf;
  1721.   
  1722. !     gate = relative(master_directory, "GATE");
  1723. !     gf = open_file(gate, mode);
  1724. !     err = NULL;
  1725. !     switch (mode) {
  1726. !      case OPEN_READ:
  1727. !     if (gf != NULL) {
  1728. !         if (unlink(gate) == 0) break;
  1729. !         err = "unlink";
  1730. !         break;
  1731. !     }
  1732. !     if (errno != ENOENT) err = "read";
  1733. !     break;
  1734. !     
  1735. !      default:
  1736. !     if (gf != NULL) chmod(gate, 0644); /* override restrictive umask */
  1737. !     /* caller must complain if cannot open! */
  1738. !     break;
  1739. !     }
  1740.   
  1741. !     if (err != NULL) {
  1742. !     sys_warning("Cannot %s %s (err=%d).  Check modes!!", err, gate, errno);
  1743. !     if (gf != NULL) fclose(gf);
  1744. !     return NULL;
  1745. !     }
  1746. !     return gf;
  1747.   }
  1748.   
  1749.   send_master(command, gh, opt, arg)
  1750. ***************
  1751. *** 153,159 ****
  1752.   {
  1753.       FILE *gate;
  1754.   
  1755. !     gate = open_file(relative(master_directory, "GATE"), OPEN_APPEND);
  1756.   
  1757.       if (gate == NULL) {
  1758.       printf("Cannot send to master (check GATE file)\n");
  1759. --- 224,230 ----
  1760.   {
  1761.       FILE *gate;
  1762.   
  1763. !     gate = open_gate_file(OPEN_APPEND);
  1764.   
  1765.       if (gate == NULL) {
  1766.       printf("Cannot send to master (check GATE file)\n");
  1767. *** ./LAST/term.c    Fri Oct  5 19:07:20 1990
  1768. --- term.c    Wed Nov 28 21:07:00 1990
  1769. ***************
  1770. *** 41,46 ****
  1771. --- 41,47 ----
  1772.   export int  flow_control = 1;
  1773.   export int  use_visible_bell = 1; /* if supported by terminal */
  1774.   export int  ignore_xon_xoff = 1;
  1775. + export int  multi_key_guard_time = 2; /* tenths of a second */
  1776.   
  1777.   export key_type help_key = '?';
  1778.   export key_type comp1_key = SP;
  1779. ***************
  1780. *** 101,108 ****
  1781.   int  cookie_size;    /* size of magic cookie */
  1782.   int  two_cookies;    /* space needed to enter&exit standout mode */
  1783.   int  STANDOUT;        /* terminal got standout mode */
  1784. - int  WRAP;        /* terminal got automatic margins */
  1785.   
  1786.   #ifdef HAVE_TERMIO
  1787.   
  1788.   #define KEY_BURST 50    /* read bursts of 50 chars (or timeout after 100 ms) */
  1789. --- 102,116 ----
  1790.   int  cookie_size;    /* size of magic cookie */
  1791.   int  two_cookies;    /* space needed to enter&exit standout mode */
  1792.   int  STANDOUT;        /* terminal got standout mode */
  1793.   
  1794. + #ifdef FAKE_INTERRUPT
  1795. + #include <setjmp.h>
  1796. + extern jmp_buf fake_keyb_sig;
  1797. + extern int arm_fake_keyb_sig;
  1798. + extern char fake_keyb_siglist[];
  1799. + #endif
  1800.   #ifdef HAVE_TERMIO
  1801.   
  1802.   #define KEY_BURST 50    /* read bursts of 50 chars (or timeout after 100 ms) */
  1803. ***************
  1804. *** 122,135 ****
  1805.   
  1806.   #else    /* V7/BSD TTY DRIVER */
  1807.   
  1808. - #ifdef FAKE_INTERRUPT
  1809. - #include <setjmp.h>
  1810. - extern jmp_buf fake_keyb_sig;
  1811. - extern int arm_fake_keyb_sig;
  1812. - extern char fake_keyb_siglist[];
  1813. - #endif
  1814.   #include <sgtty.h>
  1815.   
  1816.   static struct sgttyb norm_tty, raw_tty;
  1817. --- 130,135 ----
  1818. ***************
  1819. *** 169,174 ****
  1820. --- 169,193 ----
  1821.   
  1822.   #endif  /* USE_TERMCAP */
  1823.   
  1824. + /*
  1825. +  * timeout in n/10 seconds via SIGALRM
  1826. +  */
  1827. + micro_alarm(n)
  1828. + int n;
  1829. + {
  1830. + #ifdef HAVE_UALARM
  1831. +     ualarm(n<=1 ? 100000 : n*100000, 0); /* 4.3 BSD ualarm() */
  1832. + #else
  1833. + #ifdef MICRO_ALARM
  1834. +     if (n <= 0) n = 1;
  1835. +     MICRO_ALARM(n);            /* System specific timeout */
  1836. + #else
  1837. +     alarm(n <= 10 ? 1 : (n+9)/10);    /* Standard alarm() call */
  1838. + #endif
  1839. + #endif
  1840. + }
  1841.   static int multi_keys = 0;
  1842.   
  1843.   static struct multi_key {
  1844. ***************
  1845. *** 350,356 ****
  1846.       Columns = columns;
  1847.       Lines = lines;
  1848.       cookie_size = magic_cookie_glitch;
  1849. -     WRAP = auto_right_margin;
  1850.       if (use_visible_bell && HAS_CAP(flash_screen))
  1851.       strcpy(bell_str, flash_screen);
  1852.       else if (HAS_CAP(bell))
  1853. --- 369,374 ----
  1854. ***************
  1855. *** 391,397 ****
  1856.   
  1857.       cookie_size = tgetnum("sg");
  1858.   
  1859. -     WRAP = tgetflag("am");
  1860.       ceol_standout_glitch = tgetflag("xs");
  1861.   
  1862.       opt_cap("ti", enter_ca_mode);
  1863. --- 409,414 ----
  1864. ***************
  1865. *** 451,457 ****
  1866.       ospeed = norm_tty.sg_ospeed;
  1867.       set_term_speed((unsigned long)ospeed);
  1868.   
  1869. !     raw_tty.sg_flags &= ~ECHO;
  1870.   #ifdef CBREAK
  1871.   #ifdef SV_INTERRUPT            /* make read from tty interruptable */
  1872.       siginterrupt(SIGTSTP, 1);        /* this is necessary to redraw screen */
  1873. --- 468,474 ----
  1874.       ospeed = norm_tty.sg_ospeed;
  1875.       set_term_speed((unsigned long)ospeed);
  1876.   
  1877. !     raw_tty.sg_flags &= ~(ECHO | CRMOD);
  1878.   #ifdef CBREAK
  1879.   #ifdef SV_INTERRUPT            /* make read from tty interruptable */
  1880.       siginterrupt(SIGTSTP, 1);        /* this is necessary to redraw screen */
  1881. ***************
  1882. *** 697,704 ****
  1883.   static int is_raw = 0;
  1884.   
  1885.   #ifdef HAVE_TERMIO
  1886. ! #define RAW_MODE_ON    ioctl(0, TCSETAF, &raw_tty)
  1887. ! #define RAW_MODE_OFF   ioctl(0, TCSETAF, &norm_tty)
  1888.   #else
  1889.   #define RAW_MODE_ON    ioctl(0, TIOCSETP, &raw_tty)
  1890.   #define RAW_MODE_OFF   ioctl(0, TIOCSETP, &norm_tty)
  1891. --- 714,721 ----
  1892.   static int is_raw = 0;
  1893.   
  1894.   #ifdef HAVE_TERMIO
  1895. ! #define RAW_MODE_ON    ioctl(0, TCSETAW, &raw_tty)
  1896. ! #define RAW_MODE_OFF   ioctl(0, TCSETAW, &norm_tty)
  1897.   #else
  1898.   #define RAW_MODE_ON    ioctl(0, TIOCSETP, &raw_tty)
  1899.   #define RAW_MODE_OFF   ioctl(0, TIOCSETP, &norm_tty)
  1900. ***************
  1901. *** 814,819 ****
  1902. --- 831,1042 ----
  1903.   
  1904.   #endif /* CBREAK */
  1905.   
  1906. + #ifndef USE_OLD_GET_C_CODE
  1907. + #ifndef KEY_BURST
  1908. + #define KEY_BURST 32
  1909. + #endif
  1910. + #define RD_PUSHBACK 10
  1911. + static char rd_buffer[KEY_BURST+RD_PUSHBACK];    /* Holds stuff from read */
  1912. + static char *rd_ptr;
  1913. + static int rd_count = 0, rd_alarm = 0;
  1914. + #ifdef FAKE_INTERRUPT
  1915. + static jmp_buf fake_alarm_sig;
  1916. + #endif
  1917. + static rd_timeout()
  1918. + {
  1919. +     rd_alarm = 1;
  1920. + #ifdef FAKE_INTERRUPT
  1921. +     longjmp(fake_alarm_sig, 1);
  1922. + #endif
  1923. + }
  1924. + #define RD_TIMEOUT    0x1000
  1925. + #define RD_INTERRUPT    0x1001
  1926. + static int read_char_kbd(tmo)
  1927. + int tmo;    /* timeout if no input arrives */
  1928. + {
  1929. +     if (rd_count <= 0) {
  1930. +     if (tmo) {
  1931. + #ifdef FAKE_INTERRUPT
  1932. +         if (setjmp(fake_alarm_sig)) goto tmout;
  1933. + #endif
  1934. +         rd_alarm = 0;
  1935. +         signal(SIGALRM, rd_timeout);
  1936. +         micro_alarm(multi_key_guard_time);
  1937. +     }
  1938. +     rd_ptr = rd_buffer + RD_PUSHBACK;
  1939. +     rd_count = read(0, rd_ptr, KEY_BURST);
  1940. +     if (tmo) {
  1941. +         if (rd_alarm) goto tmout;
  1942. +         alarm(0);
  1943. +     }
  1944. +     if (rd_count < 0) {
  1945. +         if (errno != EINTR) s_hangup++;
  1946. +         return RD_INTERRUPT;
  1947. +     }
  1948. +     }
  1949. +     --rd_count;
  1950. +     return *rd_ptr++;
  1951. +     
  1952. +  tmout:
  1953. +     rd_count = 0;
  1954. +     return RD_TIMEOUT;
  1955. + }
  1956. + static unread_char(c)
  1957. + char c;
  1958. + {
  1959. +     if (rd_ptr == rd_buffer) return;
  1960. +     rd_count++;
  1961. +     *--rd_ptr = c;
  1962. + }
  1963. + flush_input()
  1964. + {
  1965. +     int arg;
  1966. +     
  1967. +     BATCH_CHECK;
  1968. + #ifdef HAVE_TERMIO
  1969. +     ioctl(0, TCFLSH, 0);
  1970. + #else
  1971. + #ifdef FREAD
  1972. +     arg = FREAD;
  1973. +     ioctl(0, TIOCFLUSH, &arg);
  1974. + #else
  1975. +     ioctl(0, TIOCFLUSH, 0);
  1976. + #endif
  1977. + #endif
  1978. +     rd_count = 0;
  1979. + }
  1980. + int enable_stop = 1;
  1981. + static int do_macro_processing = 1;
  1982. + get_c()
  1983. + {
  1984. +     key_type c, first_key;
  1985. +     int key_cnt, mc, n;
  1986. +     register struct multi_key *mk, *multi_match;
  1987. +     register int i;
  1988. +  next_key:
  1989. +     if (s_hangup) return K_interrupt;
  1990. +     if (do_macro_processing)
  1991. +     switch (m_getc(&mc)) {
  1992. +      case 0: break;
  1993. +      case 1: return mc;
  1994. +      case 2: return K_interrupt;
  1995. +     }
  1996. + #ifdef RESIZING
  1997. +     if (s_resized) goto redraw;
  1998. + #endif
  1999. +     if (batch_mode)
  2000. +     user_error("Attempt to read keyboard input in batch mode");
  2001. +     for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
  2002. +     mk->cur_key = mk->keys;
  2003. +     key_cnt = 0;
  2004. + #ifdef FAKE_INTERRUPT
  2005. +     if (setjmp(fake_keyb_sig)) goto intr;
  2006. +     arm_fake_keyb_sig = 1;
  2007. + #endif
  2008. +  multi:
  2009. +     switch (n = read_char_kbd(key_cnt)) {
  2010. +      case RD_INTERRUPT:
  2011. + #ifdef CBREAK
  2012. +     if (s_redraw) goto redraw;
  2013. + #endif
  2014. + #ifdef RESIZING
  2015. +     if (s_resized) goto redraw;
  2016. + #endif
  2017. +     goto intr;
  2018. +      case RD_TIMEOUT:
  2019. +     while (--key_cnt > 0) unread_char(multi_match->keys[key_cnt]);
  2020. +     c = first_key;
  2021. +     goto got_char;
  2022. +     
  2023. +      default:
  2024. +     c = (key_type)n;
  2025. +     if (data_bits < 8) c &= 0x7f;
  2026. +     if (ignore_xon_xoff)
  2027. +         if (c == CONTROL_('Q') || c == CONTROL_('S')) goto multi;
  2028. +     break;
  2029. +     }
  2030. +     multi_match = NULL;
  2031. +     for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) {
  2032. +     if (mk->cur_key == NUL) continue;
  2033. +     if (*(mk->cur_key)++ != c) {
  2034. +         mk->cur_key = NUL;
  2035. +         continue;
  2036. +     }
  2037. +     if (*(mk->cur_key) == NUL) {
  2038. +         c = mk->code;
  2039. +         goto got_char;
  2040. +     }
  2041. +     multi_match = mk;
  2042. +     }
  2043. +     if (multi_match) {
  2044. +     if (key_cnt == 0) first_key = c;
  2045. +     key_cnt++;
  2046. +     goto multi;
  2047. +     }
  2048. +     if (key_cnt) {
  2049. +     if (key_cnt == 1 && first_key == 033) {
  2050. +         unread_char(c);
  2051. +         c = 033;
  2052. +         goto got_char;
  2053. +     }
  2054. +     ding();
  2055. +     flush_input();
  2056. +     goto next_key;
  2057. +     }
  2058. +  got_char:
  2059. + #ifdef FAKE_INTERRUPT
  2060. +     arm_fake_keyb_sig = 0;
  2061. + #endif
  2062. +     c = global_key_map[c];
  2063. + #ifndef CBREAK
  2064. +     if (c == IntrC) return K_interrupt;    /* don't flush */
  2065. +     if (c == SuspC) {
  2066. +     if (enable_stop && suspend_nn()) goto redraw;
  2067. +     goto next_key;
  2068. +     }
  2069. + #endif
  2070. +     return (int)c;
  2071. +  intr:
  2072. + #ifdef FAKE_INTERRUPT
  2073. +     arm_fake_keyb_sig = 0;
  2074. + #endif
  2075. +     rd_count = 0;
  2076. +     return K_interrupt;
  2077. +  redraw:
  2078. + #ifdef RESIZING
  2079. +     s_resized = 0;
  2080. + #endif
  2081. +     s_redraw = 0;
  2082. +     return GETC_COMMAND | K_REDRAW;
  2083. + }
  2084. + #else /* original code */
  2085.   static int do_flush_input = 0;
  2086.   
  2087.   flush_input()
  2088. ***************
  2089. *** 947,957 ****
  2090.           first_key = c;
  2091.           alarm_on = 1;
  2092.           signal(SIGALRM, mk_timeout);
  2093. ! #ifdef MICRO_ALARM
  2094. !         MICRO_ALARM();
  2095. ! #else
  2096. !         sleep(1);
  2097. ! #endif
  2098.           }
  2099.   #endif
  2100.           key_cnt++;
  2101. --- 1170,1176 ----
  2102.           first_key = c;
  2103.           alarm_on = 1;
  2104.           signal(SIGALRM, mk_timeout);
  2105. !         micro_alarm(1);
  2106.           }
  2107.   #endif
  2108.           key_cnt++;
  2109. ***************
  2110. *** 1022,1027 ****
  2111. --- 1241,1247 ----
  2112.       return (int)c;
  2113.   }
  2114.   
  2115. + #endif
  2116.   
  2117.   /*
  2118.    * read string with completion, pre-filling, and break on first char
  2119. *** ./LAST/term.h    Mon Apr 23 18:25:52 1990
  2120. --- term.h    Wed Nov 28 21:06:59 1990
  2121. ***************
  2122. *** 18,24 ****
  2123.   
  2124.   extern int Lines, Columns;
  2125.   extern int cookie_size;
  2126. ! extern int WRAP, STANDOUT;
  2127.   
  2128.   extern char *get_s();
  2129.   
  2130. --- 18,24 ----
  2131.   
  2132.   extern int Lines, Columns;
  2133.   extern int cookie_size;
  2134. ! extern int STANDOUT;
  2135.   
  2136.   extern char *get_s();
  2137.   
  2138. *** ./LAST/variable.c    Wed Nov  7 15:54:56 1990
  2139. --- variable.c    Wed Nov 28 15:03:11 1990
  2140. ***************
  2141. *** 186,191 ****
  2142. --- 186,192 ----
  2143.       also_read_articles,
  2144.       article_limit,
  2145.       auto_read_limit,
  2146. +     check_db_update,
  2147.       conf_entry_limit,
  2148.       collapse_subject,
  2149.       Columns,
  2150. ***************
  2151. *** 197,202 ****
  2152. --- 198,204 ----
  2153.       first_page_lines,
  2154.       fmt_linenum,
  2155.       kill_debug,
  2156. +     kill_ref_count,
  2157.       Lines,
  2158.       match_skip_prefix,
  2159.       mark_next_group,
  2160. ***************
  2161. *** 204,209 ****
  2162. --- 206,212 ----
  2163.       mark_read_skip,
  2164.       message_history,
  2165.       min_pv_window,
  2166. +     multi_key_guard_time,
  2167.       new_group_action,
  2168.       newsrc_update_freq,
  2169.       orig_to_include_mask,
  2170. ***************
  2171. *** 294,299 ****
  2172. --- 297,303 ----
  2173.       "backup-suffix",        STR 0,        (char **)&bak_suffix,
  2174.       "bug-report-address",     STR 0,        (char **)&bug_address,
  2175.       "case-fold-search",        BOOL 0,        (char **)&case_fold_search,
  2176. +     "check-db-update-time",    INT 0,        (char **)&check_db_update,
  2177.       "check-group-access",    BOOL 0,        (char **)&check_group_access,
  2178.       "collapse-subject",        INT 3,        (char **)&collapse_subject,
  2179.       "columns",            INT 1,        (char **)&Columns,
  2180. ***************
  2181. *** 353,358 ****
  2182. --- 357,363 ----
  2183.       "kill",            BOOL 0,        (char **)&do_kill_handling,
  2184.       "kill-debug",        BOOL 0,        (char **)&kill_debug,
  2185.       "kill-key",            KEY 0,        (char **)&kill_key,
  2186. +     "kill-reference-count",    INT 0,        (char **)&kill_ref_count,
  2187.       "layout",            INT 1,        (char **)&fmt_linenum,
  2188.       "limit",            INT 2,        (char **)&article_limit,
  2189.       "lines",            INT 1,        (char **)&Lines,
  2190. ***************
  2191. *** 375,380 ****
  2192. --- 380,386 ----
  2193.       "mmdf-format",        BOOL 0,        (char **)&use_mmdf_folders,
  2194.       "monitor",            BOOL 0,        (char **)&monitor_mode,
  2195.       "motd",            BOOL 0,        (char **)&show_motd_on_entry,
  2196. +     "multi-key-guard-time",    INT 0,        (char **)&multi_key_guard_time,
  2197.       "new-group-action",        INT 0,        (char **)&new_group_action,
  2198.       "new-style-read-prompt",    BOOL 0,        (char **)&new_read_prompt,
  2199.       "news-header",        STR 0,        (char **)&extra_news_headers,
  2200. *** ./LAST/xmakefile    Wed Nov  7 15:54:57 1990
  2201. --- xmakefile    Mon Dec 10 15:44:26 1990
  2202. ***************
  2203. *** 72,78 ****
  2204.   
  2205.   SHELL = /bin/sh
  2206.   
  2207. ! MASTER = master.o collect.o expire.o proto.o \
  2208.       global.o options.o active.o db.o nntp.o \
  2209.       pack_date.o pack_name.o pack_subject.o news.o digest.o
  2210.   
  2211. --- 72,78 ----
  2212.   
  2213.   SHELL = /bin/sh
  2214.   
  2215. ! MASTER = master.o collect.o expire.o proto.o hostname.o \
  2216.       global.o options.o active.o db.o nntp.o \
  2217.       pack_date.o pack_name.o pack_subject.o news.o digest.o
  2218.   
  2219. ***************
  2220. *** 83,89 ****
  2221.       answer.o reroute.o hostname.o save.o unshar.o decode.o execute.o \
  2222.       pack_date.o pack_name.o pack_subject.o news.o digest.o match.o
  2223.   
  2224. ! ACCT = account.o global.o options.o proto.o
  2225.   
  2226.   MAIL = nnmail.o reroute.o hostname.o global.o options.o
  2227.   
  2228. --- 83,89 ----
  2229.       answer.o reroute.o hostname.o save.o unshar.o decode.o execute.o \
  2230.       pack_date.o pack_name.o pack_subject.o news.o digest.o match.o
  2231.   
  2232. ! ACCT = account.o global.o options.o proto.o hostname.o 
  2233.   
  2234.   MAIL = nnmail.o reroute.o hostname.o global.o options.o
  2235.   
  2236.